package com.csw.encryptiontechnology.linux;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import lombok.extern.slf4j.Slf4j;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.yaml.snakeyaml.Yaml;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class LinuxUtils {
    private static final ExecutorService executor = Executors.newCachedThreadPool();

    public static void installDocker(String host, int port, String username, String password) {
//        String host = "your_server_ip";
//        int port = 22;
//        String username = "your_username";
//        String password = "your_password";

        try {
            com.jcraft.jsch.Session session = getSession(host, port, username, password);

            // 检查是否安装了 Docker
            String command = "docker version";
            ChannelExec channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(command);
            channel.connect();

            BufferedReader reader = new BufferedReader(new InputStreamReader(channel.getInputStream()));
            String line;
            boolean dockerInstalled = true;
            while ((line = reader.readLine()) != null) {
                if (line.contains("command not found")) {
                    dockerInstalled = false;
                    break;
                }
            }
            reader.close();

            if (!dockerInstalled) {
                // 如果没有安装 Docker，则进行安装
                command = "curl -fsSL https://get.docker.com | sh";
                channel = (ChannelExec) session.openChannel("exec");
                channel.setCommand(command);
                channel.connect();
                reader = new BufferedReader(new InputStreamReader(channel.getInputStream()));
                while ((line = reader.readLine()) != null) {
                    System.out.println(line);
                }
                reader.close();
                System.out.println("Docker 安装完成。");
            } else {
                System.out.println("服务器上已安装 Docker。");
            }

            channel.disconnect();
            session.disconnect();
        } catch (JSchException | IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * mysql单实例安装
     */
    public static void mysqlInstallDan(String hostname, int port, String username, String password) {
//        String hostname = "your_remote_server_ip";
//        int port = 22;
//        String username = "your_username";
//        String password = "your_password";

        try {
            com.jcraft.jsch.Session session = getSession(hostname, port, username, password);

            boolean b = judgeCommandSearch(session, "docker images", "mysql", "5.7");
            if (b == false) {
                // 拉取 MySQL 镜像
                String pullCommand = "docker pull mysql:5.7";
                runExec(session, pullCommand, "Pulling: ");
            }
            String upperCase = Long.toUnsignedString(IdUtil.getSnowflake().nextId(), 36).toUpperCase();
            Random random = new Random();
            int i = random.nextInt(9000) + 1000;

//            // 上传 Tomcat 安装包并解压
//            String uploadCommand = "scp /path/to/tomcat.tar.gz " + username + "@" + host + ":/home/";
//// 解压
//            String extractCommand = "tar -zxvf tomcat.tar.gz";
//// 启动 Tomcat
//            String startTomcatCommand = "/path/to/tomcat/bin/startup.sh";
            // 运行 MySQL 容器
            String runCommand = "docker run -di --name=csw_mysql_" + upperCase + " -p " + i + ":3306 -e MYSQL_ROOT_PASSWORD=" + upperCase + " mysql:5.7";
// String command = "docker exec your_mysql_container_name tail -n 10 /var/log/mysql/mysql.log";
//
            runExec(session, runCommand, "Running: ");
            TimeUnit.SECONDS.sleep(10);
            readLog(session, "docker logs csw_mysql_" + upperCase);

            session.disconnect();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * mysql集群安装
     */
    public static void mysqlInstallMany(com.jcraft.jsch.Session session) {
        String upperCase = Long.toUnsignedString(IdUtil.getSnowflake().nextId(), 36).toLowerCase();
        String filePathQ = "/docker/" + upperCase + "/";
        String filePath = "/docker/" + upperCase + "/docker-compose.yml";
        Random random = new Random();
        //测试模拟，到时候端口号要统一管理
        int i = random.nextInt(55534) + 10000;
        int i1 = i + 1;

        try {
            // 读取配置文件
//            Properties properties = new Properties();
//            try (InputStream inputStream = DockerInstaller.class.getClassLoader().getResourceAsStream("docker-compose.yml")) {
//                if (inputStream != null) {
//                    properties.load(inputStream);
//                }
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//             //输出当前配置
//            System.out.println("Before modification:");
//            System.out.println("key1: " + properties.getProperty("key1"));
//            System.out.println("key2: " + properties.getProperty("key2"));
//
//            // 修改配置
//            properties.setProperty("key1", "newValue1");
//
//            // 保存修改后的配置文件
//            FileOutputStream fos = new FileOutputStream("config.properties");
//            properties.store(fos, "Updated configuration");
//            fos.close();

            //读取yml文件，并修改端口号
            Yaml yaml = new Yaml();
            Map<String, Object> data = null;
            try (InputStream inputStream = DockerInstaller.class.getClassLoader().getResourceAsStream("docker-compose.yml")) {
                if (inputStream != null) {
                    data = yaml.load(inputStream);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            // 修改数据
            if (data == null) {
                System.out.println("读取异常");
            }
            JSONObject jsonObject = new JSONObject(data);
            JSONObject services = jsonObject.getJSONObject("services");

            JSONObject slave = services.getJSONObject("slave");

            changeInformationMysql2(slave, i1, upperCase);
            //修改端口号
            JSONObject master = services.getJSONObject("master");
            changeInformationMysql2(master, i, upperCase);

//            services.put("mater111", services.getJSONObject("master"));
//            services.remove("master");
//            services.put("slave111", services.getJSONObject("slave"));
//            services.remove("slave");


            Map<String, Object> res = jsonObject.toJavaObject(Map.class);
            File fileDirect = new File(filePathQ);
            if (!fileDirect.exists()) {
                fileDirect.mkdirs();
            }
            File file = new File(filePath);

            if (!file.exists()) {
                file.createNewFile();
            }
            // 写入修改后的 YAML 文件
            FileWriter writer = new FileWriter(file);
            yaml.dump(res, writer);
            writer.flush();
            writer.close();


        } catch (Exception e) {
            e.printStackTrace();
        }


        try {
            //判断是否存在数据库，没有就创建
            boolean b = judgeCommandSearch(session, "docker images", "mysql", "5.7");
            if (b == false) {
                // 拉取 MySQL 镜像
                String pullCommand = "docker pull mysql:5.7";
                runExec(session, pullCommand, "Pulling: ");
            }


            //如果当前环境是本地需要，上传配置文件到根目录【线上会在相应的位置直接生成文件】
            runExec(session, "mkdir -p " + filePathQ, "创建目录：");
            //上传配置文件
//            uploadFwq("scp " + filePath + " " + username + "@" + hostname + ":" + filePathQ);
//            try {
//                FTPClient ftpClient = new FTPClient();
//                //ftp端口是21
//                ftpClient.connect(hostname, 21);
//                ftpClient.login(username, password);
//                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
//
//                FileInputStream fis = new FileInputStream(filePath);
//                boolean success = ftpClient.storeFile(filePathQ, fis);
//                if (success) {
//                    System.out.println("File uploaded successfully.");
//                } else {
//                    System.out.println("File upload failed.");
//                }
//
//                fis.close();
//                ftpClient.logout();
//                ftpClient.disconnect();
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//            try {
//                Process process = Runtime.getRuntime().exec("scp " + filePath + " " + username + "@" + hostname + ":" + filePathQ);
//
//                // 读取标准输出
//                BufferedReader stdInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
//
//                // 读取标准错误输出
//                BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
//
//                String s;
//                System.out.println("Standard output:");
//                while ((s = stdInput.readLine()) != null) {
//                    System.out.println(s);
//                }
//
//                System.out.println("Standard error:");
//                while ((s = stdError.readLine()) != null) {
//                    System.out.println(s);
//                }
//
//                int exitCode = process.waitFor();
//                if (exitCode == 0) {
//                    System.out.println("File uploaded successfully.");
//                } else {
//                    System.out.println("File upload failed. Exit code: " + exitCode);
//                }
//            } catch (IOException | InterruptedException e) {
//                e.printStackTrace();
//            }
            /**【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【【
             * 本地测试，在这一步要把包传到linux的相应目录
             */
            //执行启动命令
            runExec(session, "docker-compose -f " + filePath + " -p project_name_" + upperCase + " up -d", "执行启动命令：");
            TimeUnit.SECONDS.sleep(10);
            List<String> masterList = new ArrayList<>();
            //进入数据库1容器
            masterList.add("docker exec -it project_name_" + upperCase + "-master-1 bash");
            //进入数据库1
            masterList.add("mysql  -uroot -p" + upperCase);
            //创建用户
            masterList.add("CREATE USER 'replica'@'%' IDENTIFIED BY 'replica';");
            //赋予权限
            masterList.add("GRANT REPLICATION SLAVE ON *.* TO 'replica'@'%';");
            //查看状态
            masterList.add("SHOW MASTER STATUS \\G ");

            Map<String, String> mapReturn = runShell(session, masterList, "执行主节点");

            //设置资源限制
            setResourceRestrictions(session, "project_name_" + upperCase + "-master-1");

            //读取master的logfile
            String masterLogFile = mapReturn.get("File");
            //读取master的logpos
            String masterLogPos = mapReturn.get("Position");

            List<String> slaveList = new ArrayList<>();
            //进入数据库2容器
            slaveList.add("docker exec -it project_name_" + upperCase + "-slave-1 bash");
            //进入数据库2
            slaveList.add("mysql  -uroot -p" + upperCase);
            //配置数据同步
            slaveList.add("CHANGE MASTER TO MASTER_HOST='project_name_" + upperCase + "-master-1',MASTER_USER='replica',MASTER_PASSWORD='replica',MASTER_LOG_FILE='" + masterLogFile.trim() + "',MASTER_LOG_POS=" + masterLogPos.trim() + ";");
            //启动从库
            slaveList.add("START SLAVE;");
            slaveList.add("show slave status \\G");
            //里面的master_id就是主节点的server_uuid;进入主节点搜SHOW GLOBAL VARIABLES LIKE 'server_uuid';
            runShellNotLog(session, slaveList, "配置从节点");

            //设置资源限制
            setResourceRestrictions(session, "project_name_" + upperCase + "-slave-1");

            //

//            // 上传 Tomcat 安装包并解压
//            String uploadCommand = "scp /path/to/tomcat.tar.gz " + username + "@" + host + ":/home/";
//// 解压
//            String extractCommand = "tar -zxvf tomcat.tar.gz";
//// 启动 Tomcat
//            String startTomcatCommand = "/path/to/tomcat/bin/startup.sh";
            // 运行 MySQL 容器


        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
    }

    private static void setResourceRestrictions(com.jcraft.jsch.Session session, String projectName) {
        //设置扩缩容
        runExec(session, "docker update --cpus 1 --memory 500m --memory-swap 500m " + projectName, "设置容器的资源限制");
        //重启
        runExec(session, "docker restart " + projectName, "重启容器");
        //查看
        //docker inspect project_name_e0c20lsr6m0w-master-1
    }


    private static void changeInformationMysql2(JSONObject slave, int i1, String rootPassword) {
        //修改端口号
        JSONArray slavePorts = slave.getJSONArray("ports");
        slavePorts.remove(0);
        slavePorts.add(0, i1 + ":3306");
        //修改root密码
        JSONObject environment = slave.getJSONObject("environment");
        environment.put("MYSQL_ROOT_PASSWORD", rootPassword);
    }

    public static com.jcraft.jsch.Session getSession(String hostname, int port, String username, String password) throws JSchException {
        JSch jsch = new JSch();

        com.jcraft.jsch.Session session = jsch.getSession(username, hostname, port);
        session.setPassword(password);
        session.setConfig("StrictHostKeyChecking", "no");
        session.connect();
        return session;
    }

    /**
     * 运行命令
     *
     * @throws IOException
     */
    public static void runExec(com.jcraft.jsch.Session session, String runCommand, String x) {
        System.out.println(runCommand);
        ChannelExec runChannel = null;
        try {
            runChannel = (ChannelExec) session.openChannel("exec");
            runChannel.setCommand(runCommand);
            runChannel.connect();
            BufferedReader runReader = new BufferedReader(new InputStreamReader(runChannel.getInputStream()));
            String runLine;
            while ((runLine = runReader.readLine()) != null) {
                System.out.println(runLine);
            }
            TimeUnit.SECONDS.sleep(1);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            runChannel.disconnect();
        }
    }

    public static Map<String, String> runShell(com.jcraft.jsch.Session session, List<String> runCommandList, String x) throws JSchException, IOException {
        System.out.println(x);
        ChannelShell channelShell = null;
        try {
            // 打开ChannelShell通道
            channelShell = (ChannelShell) session.openChannel("shell");
            channelShell.connect();

            // 获取输入输出流
            InputStream inputStream = channelShell.getInputStream();
            OutputStream outputStream = channelShell.getOutputStream();

            // 创建读取输入流的缓冲读取器
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));


//            // 发送命令到远程Shell
//            runCommand = "docker exec -it project_name_dz5f1k8vru2o-master-1 bash\n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
//
//            runCommand = "mysql -uroot -pdz5f1k8vru2o\n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
//
//            runCommand = "SHOW MASTER STATUS \\G \n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
            runCommandList.forEach(a -> {
                try {
                    a = a + "\n";
                    System.out.println(a);
                    outputStream.write(a.getBytes());
                    outputStream.flush();
                    TimeUnit.SECONDS.sleep(1);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            //最后一个命令执行完读日志
            String line;
            Map<String, String> map = new HashMap<>();
            // 读取命令执行的输出
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
                if (line.contains("Position:")) {
                    map.put("Position", line.substring(line.indexOf(":") + 1));
                }
                if (line.contains("File:")) {
                    map.put("File", line.substring(line.indexOf(":") + 1));
                }
                if (map.size() == 2) {
                    break;
                }
            }
            // 关闭通道和会话
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            channelShell.disconnect();
        }
    }

    public static void runShellNotLog(com.jcraft.jsch.Session session, List<String> runCommandList, String x) throws JSchException, IOException {
        System.out.println(x);
        ChannelShell channelShell = null;
        try {
            // 打开ChannelShell通道
            channelShell = (ChannelShell) session.openChannel("shell");
            channelShell.connect();

            // 获取输入输出流
            InputStream inputStream = channelShell.getInputStream();
            OutputStream outputStream = channelShell.getOutputStream();

            // 创建读取输入流的缓冲读取器
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));


//            // 发送命令到远程Shell
//            runCommand = "docker exec -it project_name_dz5f1k8vru2o-master-1 bash\n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
//
//            runCommand = "mysql -uroot -pdz5f1k8vru2o\n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
//
//            runCommand = "SHOW MASTER STATUS \\G \n";
//            outputStream.write(runCommand.getBytes());
//            outputStream.flush();
            runCommandList.forEach(a -> {
                try {
                    a = a + "\n";
                    System.out.println(a);
                    outputStream.write(a.getBytes());
                    outputStream.flush();
                    TimeUnit.SECONDS.sleep(1);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });

            //最后一个命令执行完读日志
            String line;
            // 读取命令执行的输出
            while ((line = reader.readLine()) != null) {
                System.out.println(line);

                if (line.contains("Master_TLS_Version")) {
                    break;
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            channelShell.disconnect();
        }
    }


    /**
     * 读取容器日志
     */
    public static void readLog(com.jcraft.jsch.Session session, String search) {
        ChannelExec pullChannel = null;
        try {
            pullChannel = (ChannelExec) session.openChannel("exec");
        } catch (JSchException e) {
            throw new RuntimeException(e);
        }

        System.out.println(search);
        pullChannel.setCommand(search);
        try {
            pullChannel.connect();
        } catch (JSchException e) {
            throw new RuntimeException(e);
        }
        BufferedReader runReader = null;
        try {
            runReader = new BufferedReader(new InputStreamReader(pullChannel.getInputStream()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        String runLine;
        while (true) {
            try {
                if (!((runLine = runReader.readLine()) != null)) break;
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            System.out.println("Running: " + runLine);
        }
        pullChannel.disconnect();
    }

    /**
     * 判断是否包含
     *
     * @param session
     * @param search
     * @param judge
     * @return
     */
    public static boolean judgeCommandSearch(com.jcraft.jsch.Session session, String search, String
            repository, String tag) {
        ChannelExec pullChannel = null;
        try {
            pullChannel = (ChannelExec) session.openChannel("exec");
        } catch (JSchException e) {
            throw new RuntimeException(e);
        }
        pullChannel.setCommand(search);
        try {
            pullChannel.connect();
        } catch (JSchException e) {
            throw new RuntimeException(e);
        }
        BufferedReader pullReader = null;
        try {
            pullReader = new BufferedReader(new InputStreamReader(pullChannel.getInputStream()));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String pullLine;
        while (true) {
            try {
                if (!((pullLine = pullReader.readLine()) != null)) break;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            if (pullLine.contains(repository) && pullLine.contains(tag)) {
                pullChannel.disconnect();
                return true;
            }
        }
        pullChannel.disconnect();
        return false;
    }

    /**
     * 用tail -f 读取日志文件
     */
    public static SseEmitter readLogTail(String hostname, int port, String username, String password, String logPath) {
        SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);

        executor.submit(() -> {
            final SSHClient sshClient = new SSHClient();
            sshClient.addHostKeyVerifier(new PromiscuousVerifier());
            try {
                sshClient.connect(hostname, port);
                sshClient.authPassword(username, password);
                try (Session session = sshClient.startSession()) {
                    String command = "tail -f " + logPath;
                    Session.Command cmd = session.exec(command);

                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()));
                         BufferedReader errorReader = new BufferedReader(new InputStreamReader(cmd.getErrorStream()))) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            emitter.send(SseEmitter.event().data(line));
                        }
                        while ((line = errorReader.readLine()) != null) {
                            emitter.send(SseEmitter.event().data("ERROR: " + line));
                        }
                        emitter.complete();
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            } catch (Exception e) {
                emitter.completeWithError(e);
            } finally {
                try {
                    sshClient.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });

        return emitter;
    }

}
